今天來看一下 Docker Compose
。Compose 這個工具的用途為定義及運行多容器的 Docker 應用程式,它的設定檔 compose file 以 YAML 格式編寫,通常會命名為 docker-compose.yml
。其實 docker-compose.yml
這個檔案在前兩天已經看過了,當時是在服務層級中編寫 docker-compose.yml
,並用 docker stack
來部署應用程式。雖然在教學文件中的這個部分有要求安裝 Docker Compose
,但在整個教學文件中都沒有用到 docker-compose
指令(它是 Docker Compose
的 CLI 工具)。究竟 Docker Compose
在整個 Docker 生態系中位於什麼位置,和 docker stack
又有什麼不同呢?問了一下 google,參考以下兩篇文章 https://vsupalov.com/difference-docker-compose-and-docker-stack/ 及 https://my.oschina.net/guol/blog/1377534,它們的差異之處大概是:
Docker Compose
的前身是 fig
,它是一個用於管理部署 Docker 容器的 Python 專案,後來變成 Docker Composer
,此工具必須要額外安裝(在 Docker for Windows
和 Docker for Mac
中已內建)。docker stack
則是包含在 Docker 引擎中的功能,內部是用 Go 編寫,必須配合 swarm 模式才能使用。Docker Compose
和 docker stack
都使用 docker-compose.yml
,但 docker stack
只支援版本 3,兩者支援的指令有些許不同。docker stack
無法 build 映像檔,須使用已經存在的映像檔。Docker Compose
更適合用在開發環境。使用 Compose 基本上可分為三個步驟:
Dockerfile
定義應用程式的環境,以便於在任何地方重新複製 (reproduce anywhere)。docker-compose.yml
定義組成應用程式的服務,使它們能在隔離的環境中一起被執行。docker-compose up
開始執行整個應用程式。Dockerfile
昨天介紹過,第二個步驟的 compose file 待會會稍作介紹,最後一個步驟則是使用 Docker Compose
的 CLI 來啟動整個服務,它的指令是 docker-compose up
。CLI 的指令請參考 https://docs.docker.com/compose/reference/overview/。隨著 swarm 被整合到 Docker 引擎,以及 docker stack
功能的開發,感覺起來 Docker Compose
可能會逐漸 deprecate,但因為 docker stack
還是會用到 compose file,所以來看一下 compose file 的編寫方式,可參考 https://docs.docker.com/compose/compose-file/。
compose file 目前的版本是第 3 版,這也是 docker stack
支援的版本,以下內容參考第 3 版文件。compose file 會定義應用程式中用到的服務 (service)、網路 (network) 及卷宗 (volume)。先來看一個文件中提供的範例:
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- "5000:80"
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- "5001:80"
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
frontend:
backend:
volumes:
db-data:
這個範例有點長,首先指明這個 compose file 的版本,下面有三個部分,分別是 services、networks、volumes。services 區段定義了 6 個服務,每個服務大致上定義了使用的映像檔、port、網路、卷宗及部署設定,networks 區段和 volumes 區段分別定義了兩個網路及一個卷宗,但沒有任何設定值。因為設定值是有階層之分的,在編寫時請注意一下每個設定值的階層關係。和往常一樣,因為設定值非常的多,大致上瞭解階層較高 (high level) 的設定值有那些就可以了。先來看一下 services 的相關設定。
docker stack
要使用事先建立 (pre-built) 的映像檔,會忽略 build 設定。這裡可以指定 build context、Dockerfile
等資訊。指定此應用程式會使用的 volume,若不存在則建立。如同昨天看到的,要建立 volume 基本上都用預設值,所以這裡只會給予 volume 名稱作為 key,若要其他的設定值請再參考文件。
指定此應用程式會使用的網路。這裡也都是使用預設值。在單一主機上預設是 bridge 橋接模式,在 swarm 中則是 overlay 模式。若需要其他的設定請再參考文件。
接下來看一下 swarm,文件說明放在 Guides > Run your app in production > Configure containers > Scale your app 之下,請參考 https://docs.docker.com/engine/swarm/。
Swarm 的基本概念在 Get Started
中已經介紹過了,就操作面而言,建立初始 swarm、加入節點、部署啟動應用程式、查看服務等等也都實作過了,這裡就翻譯一下文件中 overview 提到 swarm 模式的一些特點:
TLS
連線以確保安全。在應試目標能力中,swarm 還有一點沒提到的,就是 secret 的使用,以下稍微作一些說明。
和 Ansible Vaults 一樣,Docker secrets 的目的在處理 Docker 中會用到的機敏密資料。Docker secrets 要在 swarm 模式才能使用,並在 manager 節點集中處理,將機敏性資料加密、傳送,只有需要這份資料且被授權的容器可以使用。解密後的資料在容器中會被掛載到記憶體中的檔案系統 ( in-memory file system),路徑預設為 /run/secrets/<secret-name>
。在 Docker Compose
和 docker stack
的 compose file 中,也可以定義並使用 docker secrets。以下就跟著文件中的範例操作看看。
因為 Docker secrets 要在 swarm 模式中才能作用,所以先以目前主機的初始一個 swarm。接下來在 Docker 中加入一個 secret,內容是 "This is a secret",並將它命名為 my_secret_data
,指令如下:
$ printf "This is a secret" | docker secret create my_secret_data -
建立一個服務名為 redis
,並讓它可以存取剛才建立的 secret。
$ docker service create --name redis --secret my_secret_data redis:alpine
確認服務的執行狀況
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ylf5t25o2wl1 redis.1 redis:alpine myvm1 Running Running about an hour ago
接下來到 redis
容器中查看 secret 在容器中如何被保存。secrets 預設會存放在 /run/secrets
目錄中,以下這個指令會先找到 redis 容器的 ID,並在其中查看 /run/secrets
目錄的內容,可以看到目錄中有一個和剛才建立的 secrets 同名的檔案。
$ docker container exec $(docker ps --filter name=redis -q) ls -l /run/secrets
total 4
-r--r--r-- 1 root root 16 Nov 6 06:14 my_secret_data
同樣使用 docker container exec
指令查看這個檔案的內容。
$ docker container exec $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data
This is a secret
以上是今天的內容。這幾天從 Docker 官網的 Get Started
開始,瞭解了如何在單一容器及 Docker Swarm
部署應用程式,試著編寫 Dockerfile
以建立映像檔,將其上傳至 registry 並取回。此外還介紹了 Docker Compose
和 docker stack
,以及 Docker 網路和卷宗的類型及使用方法。想要進一步研究 Docker 的夥伴,可以參考它們的官方文件,有相當豐富的內容,並針對在生產環境場景如何使用有很多介紹。明天要進入下一個主題,Kubernetes。